package base;

import java.text.NumberFormat;

public class Util {

	
	private static NumberFormat numberFormat = NumberFormat.getInstance();

	/** Formats filesize in bytes as appropriate to Bytes, KB, MB or GB
	 *
	 * @param filesize in bytes
	 * @return formatted filesize
	 **/
	public static String formatFilesize( long filesize )
	{
		String result;
		
		if( Math.abs(filesize) < 1024 )
		{
			result = "" + filesize + " Bytes";
		}
		else if( Math.abs(filesize) < 1048576 )
		{
			result = formatFilesizeKB(filesize, 2);
		}
		else if( Math.abs(filesize) < 1073741824 )
		{
			result = formatFilesizeMB(filesize, 2);
		}
		else
		{
			result = formatFilesizeGB(filesize, 2);
		}
		
		return result;
	}
	
	
	/** Formats filesize in bytes to KB
	 *
	 * @param filesize in bytes
	 * @param fractionDigits ...
	 * @return formatted filesize
	 */	
	private static String formatFilesizeKB( long filesize, int fractionDigits )
	{

		numberFormat.setMaximumFractionDigits(fractionDigits);

		return new StringBuffer(numberFormat.format(filesize / 1024.0)).append(" KB").toString();
	} // format filesize KB
	
		
	/** Formats filesize in bytes to MB
	 *
	 * @param filesize in bytes
	 * @param fractionDigits ...
	 * @return formatted filesize
	 */	
	private static String formatFilesizeMB( long filesize, int fractionDigits )
	{
		numberFormat.setMaximumFractionDigits(fractionDigits);

		// 1048576 = 1024.0 * 1024.0
		return new StringBuffer(numberFormat.format(filesize / 1048576.0)).append(" MB").toString();
	} // format filesize MB

	
	/** Formats filesize in bytes to GB
	 *
	 * @param filesize in bytes
	 * @param fractionDigits ...
	 * @return formatted filesize
	 */	
	private static String formatFilesizeGB( long filesize, int fractionDigits )
	{
		numberFormat.setMaximumFractionDigits(fractionDigits);

		// 1048576 = 1024.0 * 1024.0
		return new StringBuffer(numberFormat.format(filesize / 1073741824.0)).append(" GB").toString();
	} // format filesize GB
	

	
	public static long calculateChecksum(byte[] buf) {
		int length = buf.length;
		int i = 0;

		long sum = 0;
		long data;

		// Handle all pairs
		while (length > 1) {
			data = (((buf[i] << 8) & 0xFF00) | ((buf[i + 1]) & 0xFF));
			sum += data;
			// 1's complement carry bit correction in 16-bits (detecting sign
			// extension)
			if ((sum & 0xFFFF0000) > 0) {
				sum = sum & 0xFFFF;
				sum += 1;
			}

			i += 2;
			length -= 2;
		}

		// Handle remaining byte in odd length buffers
		if (length > 0) {
			sum += (buf[i] << 8 & 0xFF00);
			// 1's complement carry bit correction in 16-bits (detecting sign
			// extension)
			if ((sum & 0xFFFF0000) > 0) {
				sum = sum & 0xFFFF;
				sum += 1;
			}
		}

		sum = ~sum;
		sum = sum & 0xFFFF;
		return sum;

	}

	public static short bytesToShort(byte[] bytes) {
		short retorno = 0;
		retorno |= (bytes[0] & 0xFF);
		retorno <<= 8;
		retorno |= (bytes[1] & 0xFF);

		return retorno;
	}

	public static byte[] shortToBytes(short num) {
		byte[] retorno = new byte[2];

		retorno[0] = (byte) ((num >> 8) & 0xFF);
		retorno[1] = (byte) (num & 0xFF);

		return retorno;
	}

	public static int bytesToInt(byte[] bytes) {
		int retorno = 0;
		retorno |= (bytes[0] & 0xFF);
		retorno <<= 8;
		retorno |= (bytes[1] & 0xFF);
		retorno <<= 8;
		retorno |= (bytes[2] & 0xFF);
		retorno <<= 8;
		retorno |= (bytes[3] & 0xFF);

		return retorno;
	}

	public static byte[] intToBytes(int num) {
		byte[] retorno = new byte[4];
		retorno[0] = (byte) ((num >> 24) & 0xFF);
		retorno[1] = (byte) ((num >> 16) & 0xFF);
		retorno[2] = (byte) ((num >> 8) & 0xFF);
		retorno[3] = (byte) (num & 0xFF);

		return retorno;
	}

	public static long bytesToLong(byte[] bytes) {
		long retorno = 0;
		retorno |= (bytes[0] & 0xFF);
		retorno <<= 8;
		retorno |= (bytes[1] & 0xFF);
		retorno <<= 8;
		retorno |= (bytes[2] & 0xFF);
		retorno <<= 8;
		retorno |= (bytes[3] & 0xFF);
		retorno <<= 8;
		retorno |= (bytes[4] & 0xFF);
		retorno <<= 8;
		retorno |= (bytes[5] & 0xFF);
		retorno <<= 8;
		retorno |= (bytes[6] & 0xFF);
		retorno <<= 8;
		retorno |= (bytes[7] & 0xFF);

		return retorno;
	}

	public static byte[] longToBytes(long num) {
		byte[] retorno = new byte[8];
		retorno[0] = (byte) ((num >> 56) & 0xFF);
		retorno[1] = (byte) ((num >> 48) & 0xFF);
		retorno[2] = (byte) ((num >> 40) & 0xFF);
		retorno[3] = (byte) ((num >> 32) & 0xFF);
		retorno[4] = (byte) ((num >> 24) & 0xFF);
		retorno[5] = (byte) ((num >> 16) & 0xFF);
		retorno[6] = (byte) ((num >> 8) & 0xFF);
		retorno[7] = (byte) (num & 0xFF);

		return retorno;
	}

	public static int reverte(int num) {
		int retorno = 0;
		int mask = 0x00000001;
		for (int i = 0; i < 32; i++) {
			retorno |= (((num & mask) >>> i) << (31 - i));
			mask <<= 1;
		}

		return retorno;
	}

	public static int numbits(int num) {
		int retorno = 0;
		int mask = 0x00000001;

		for (int i = 0; i < 32; i++) {
			if ((num & mask) != 0) {
				retorno++;
			}
			mask <<= 1;
		}

		return retorno;
	}

	public static int criptografar(int num) {
		int retorno = num;
		int bits = numbits(retorno);
		for (int i = 0; i < bits; i++) {
			retorno = reverte(retorno);
			retorno += bits;
		}

		return retorno;
	}
}
